package com.xhwl.data.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xhwl.common.dto.cent.sdata.AreaDTO;
import com.xhwl.common.dto.cent.sdata.space.ErrorSpace;
import com.xhwl.common.enums.OperationTypeEnum;
import com.xhwl.common.enums.OrganizationTypeEnum;
import com.xhwl.common.pojo.ResultJson;
import com.xhwl.common.pojo.cent.sdata.*;
import com.xhwl.common.query.cent.sdata.BlockQuery;
import com.xhwl.common.query.cent.sdata.OrganizationQuery;
import com.xhwl.common.utils.StringUtils;
import com.xhwl.data.dao.IBlockDao;
import com.xhwl.data.dao.IOrganizationDao;
import com.xhwl.data.pojo.annotation.OrganizationHandle;
import com.xhwl.data.service.IBlockService;
import com.xhwl.data.service.IOrganizationService;
import com.xhwl.data.util.AutoCodeUtils;
import com.xhwl.data.util.CodePrefixConstant;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author: luyi
 * @Description:
 * @Date: Create in 16:09 2021/7/16
 */
@Service
public class BlockServiceImpl extends ServiceImpl<IBlockDao, Block> implements IBlockService {

    @Autowired
    private IBlockDao blockDao;

    @Autowired
    private IOrganizationService organizationService;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private IOrganizationDao organizationDao;

    private static final Logger log = LoggerFactory.getLogger(BlockServiceImpl.class);

    @Override
    public ResultJson batchCreate(List<Block> blocks) {
        if (blocks.isEmpty()) {
            return ResultJson.success();
        }
        List<Block> blocks1 = new ArrayList<>(blocks.size());
        IBlockService bean = applicationContext.getBean(IBlockService.class);
        for (Block block : blocks) {
            bean.create(block);
            blocks1.add(block);
        }
        return ResultJson.success("操作成功", blocks1);
    }

    @Override
    public ResultJson update(Block block) {
        Block old = blockDao.selectById(block.getId());
        if (null == old) {
            log.error("需要更新的地块 {} 信息不存在", block.getId());
            return ResultJson.fail("数据错误");
        }
        Organization organization = organizationService.getById(old.getOrganizationId());
        organization.setName(block.getName());
        organization.setSortField(block.getSortField());
        if(StringUtils.isNotEmpty(block.getCode())){
			organization.setCode(block.getCode());
		}
        if (null != block.getParentId()) {
            organization.setParentId(block.getParentId());
        }
		if (null != old.getSortField() &&!old.getSortField().equals(block.getSortField())){
			List<Organization> organizationList = organizationService.list(new OrganizationQuery().withParentId(organization.getParentId()));
			List<Integer> orgIds = organizationList.stream().filter(i->null != i.getSortField()).map(Organization::getId).collect(Collectors.toList());
			UpdateWrapper<Block> updateWrapper = new UpdateWrapper<>();
			updateWrapper.in("organization_id",orgIds);
			UpdateWrapper<Organization> organizationUpdateWrapper = new UpdateWrapper<>();
			organizationUpdateWrapper.in("id",orgIds);
			if (old.getSortField() > block.getSortField()){
				//大改小 小于等于'大'并且大于等于'小'的加1
				updateWrapper.ge("sort_field",block.getSortField());
				updateWrapper.le("sort_field",old.getSortField());
				organizationUpdateWrapper.ge("sort_field",block.getSortField());
				organizationUpdateWrapper.le("sort_field",old.getSortField());
				updateWrapper.setSql("sort_field = sort_field+1");
				organizationUpdateWrapper.setSql("sort_field = sort_field+1");
			}else {
				//小改大 大于'小'并且小于等于'大'的减1
				updateWrapper.le("sort_field",block.getSortField());
				updateWrapper.gt("sort_field",old.getSortField());
				organizationUpdateWrapper.le("sort_field",block.getSortField());
				organizationUpdateWrapper.gt("sort_field",old.getSortField());
				updateWrapper.setSql("sort_field = sort_field-1");
				organizationUpdateWrapper.setSql("sort_field = sort_field-1");
			}
			this.update(updateWrapper);
			organizationService.update(organizationUpdateWrapper);
		}
        ResultJson update = organizationService.update(organization);
        if (!update.getState()) {
            return update;
        }
        boolean b = this.updateById(block);
        return b ? ResultJson.success() : ResultJson.fail("数据错误");
    }

    @Override
    @Transactional
    @OrganizationHandle(operationType = OperationTypeEnum.CREATE)
    public ResultJson create(Block block) {
        this.save(block);
        if (StringUtils.isEmpty(block.getCode())) {
            String code = AutoCodeUtils.codeFormat(CodePrefixConstant.BLOCK_PREFIX, block.getId(), CodePrefixConstant.CODE_LENGTH);
            block.setCode(code);
            blockDao.updateById(block);
        }

		Organization org = organizationService.getById(block.getOrganizationId());
        org.setCode(block.getCode());
        organizationService.update(org);
		return ResultJson.success();
    }

    @Override
    public List<Block> list(BlockQuery blockQuery) {
        return blockDao.list(blockQuery);
    }

    @Override
    public ResultJson delete(Integer id) {
        Block block = blockDao.selectById(id);
        if (null == block) {
            return ResultJson.fail("数据错误");
        }
        if (organizationService.hasChild(block.getOrganizationId())) {
            return ResultJson.fail("存在下级无法删除");
        }
        organizationService.removeById(block.getOrganizationId());
        blockDao.deleteById(id);
        return ResultJson.success("删除成功");
    }

    @Override
    public Page<Block> page(BlockQuery blockQuery, Page page) {
        return blockDao.page(page, blockQuery);
    }

	@Override
	public ResultJson batchCreateFaster(List<Block> blocks) {
		if(CollectionUtils.isEmpty(blocks)){
			return ResultJson.fail("无效的数据");
		}

		List<ErrorSpace> errors = new ArrayList<>();
		// 数据处理 1 分组 2 校验
		Set<Integer> collect = blocks.stream().map(i -> i.getParentId()).collect(Collectors.toSet());
		Map<Integer, List<Block>> parentAndChildMap = new HashMap<>();
		for (Integer i : collect) {
			parentAndChildMap.put(i, blocks.stream().filter(j -> i.equals(j.getParentId())).collect(Collectors.toList()));
		}
		for(Map.Entry<Integer, List<Block>> entry : parentAndChildMap.entrySet()){
			Integer parentId = entry.getKey();
			Organization organization = organizationDao.selectById(parentId);

			// 上级信息校验
			if(null == organization){
				for (Block block : entry.getValue()) {
					ErrorSpace errorSpace = new ErrorSpace();
					errorSpace.setReason("上级信息不存在");
					errorSpace.setObj(block);
					errors.add(errorSpace);
				}
				continue;
			}

			// 名称校验
			List<Block> value = entry.getValue();
			Map<String, Block> map = new HashMap<>();
			Map<String, Block> buildingDB = new HashMap<>();
			QueryWrapper<Organization> organizationQueryWrapper = new QueryWrapper<>();
			organizationQueryWrapper.select("name");
			organizationQueryWrapper.eq("parent_id", entry.getKey());
			List<Organization> areaOrg = organizationDao.selectList(organizationQueryWrapper);
			if(!areaOrg.isEmpty()){
				for (Organization area : areaOrg) {
					buildingDB.put(area.getName(), null);
				}
			}
			for (Block block : value) {
				if(buildingDB.containsKey(block.getName()) || map.containsKey(block.getName())){
					ErrorSpace errorSpace = new ErrorSpace();
					errorSpace.setReason("名称重复");
					errorSpace.setObj(block);
					errors.add(errorSpace);
				}else{
					map.put(block.getName(), block);
				}
			}
			List<Block> correctList = new ArrayList<>();
			for(Map.Entry<String, Block> entry1 : map.entrySet()){
				correctList.add(entry1.getValue());
			}

			// code 校验
			Map<String, Block> codeMap = new HashMap<>();
			Map<String, Object> codeMapDB = new HashMap<>();
			// 这里仅校验同一个项目下的编码重复
			QueryWrapper<Organization> organizationQueryWrapper1 = new QueryWrapper<>();
			organizationQueryWrapper1.select("code");
			organizationQueryWrapper1.eq("project_id", organization.getProjectId());
			organizationQueryWrapper1.eq("type", OrganizationTypeEnum.BLOCK.id);
			organizationQueryWrapper1.isNotNull("code");
			List<Organization> organizations1 = organizationDao.selectList(organizationQueryWrapper1);
			if(!organizations1.isEmpty()){
				codeMapDB = organizations1.stream().collect(Collectors.toMap(Organization::getCode, Organization::getCode));
			}
			for (Block block : value) {
				if(!StringUtils.isEmpty(block.getCode()) && (codeMapDB.containsKey(block.getCode()) || codeMap.containsKey(block.getCode()))){
					ErrorSpace errorSpace = new ErrorSpace();
					errorSpace.setReason("编码重复");
					errorSpace.setObj(block);
					errors.add(errorSpace);
				}else{
					codeMap.put(block.getName(), block);
				}
			}
			correctList = correctList.stream().filter(i -> codeMap.containsKey(i.getName())).collect(Collectors.toList());
			if(correctList.isEmpty()){
				log.info("校验后没有合适的数据");
				continue;
			}
			try {
				this.saveBatch(correctList);
			} catch (Exception e){
				log.error("批量保存失败 {}", e.getMessage());
				for (Block block : correctList) {
					ErrorSpace errorSpace = new ErrorSpace();
					errorSpace.setReason("批量保存失败");
					errorSpace.setObj(block);
					errors.add(errorSpace);
				}
				continue;
			}
			// 保存组织信息
			List<Organization> organizations = new ArrayList<>();
			for (Block block : correctList) {
				Organization organization1 = new Organization();
				organization1.setName(block.getName());
				organization1.setParentId(block.getParentId());
				if(StringUtils.isEmpty(block.getCode())){
					String code = AutoCodeUtils.codeFormat(CodePrefixConstant.BLOCK_PREFIX, block.getId(), CodePrefixConstant.CODE_LENGTH);
					block.setCode(code);
				}
				organization1.setSortField(block.getSortField());
				organization1.setCode(block.getCode());
				organization1.setType(OrganizationTypeEnum.BLOCK.id.intValue());
				organization1.setLevel(organization.getLevel() + 1);
				organization1.setIndustryId(organization.getIndustryId());
				organization1.setEnterpriseId(organization.getEnterpriseId());
				if(null != organization.getProjectId()){
					organization1.setProjectId(organization.getProjectId());
				}
				organizations.add(organization1);
			}
			organizationService.saveBatch(organizations);

			// 统一分组下名称不会重复
			Map<String, Integer> collect1 = organizations.stream().collect(Collectors.toMap(Organization::getName, Organization::getId));

			for (Block block : correctList) {
				block.setOrganizationId(collect1.get(block.getName()));
			}
			this.updateBatchById(correctList);
		}
		return ResultJson.success();
	}

	@Override
	public ResultJson refreshSort(BlockQuery blockQuery) {
		List<Block> blocks = this.list(blockQuery);
		List<Organization> organizationList = organizationService.list(new OrganizationQuery().withIds(blocks.stream().map(Block::getOrganizationId).collect(Collectors.toList())));
		organizationList = organizationList.stream().distinct().collect(Collectors.toList());
		Map<Integer,Organization> organizationMap = organizationList.stream().collect(Collectors.toMap(Organization::getId, Function.identity()));
//        List<List<Area>> parts = Lists.partition(areas, 500);
		for (int i = 0; i < blocks.size(); i++) {
			blocks.get(i).setSortField(i+1);
			JSONObject jsonObject = JSONObject.parseObject(blocks.get(i).getExpand());
			if (null != jsonObject){
				jsonObject.put("sortField",i+1);
				blocks.get(i).setExpand(jsonObject.toJSONString());
			}
			organizationMap.get(blocks.get(i).getOrganizationId()).setSortField(i+1);
		}
		this.updateBatchById(blocks);
		organizationService.updateBatchById(organizationMap.values());
		return ResultJson.success("刷新成功");
	}
}
